package com.chinasofti.framework.net;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;


public class HttpRequestClient {
	private static final String CHARSET = HTTP.UTF_8;
	private static final String USER_AGENT = 
		"Mozilla/5.0(Linux;U;Android 2.2.1;en-us;Nexus One Build.FRG83) "
        + "AppleWebKit/553.1(KHTML,like Gecko) Version/4.0 Mobile Safari/533.1";
	private static final int GET_CONNECTION_TIMEOUT = 1000;
	private static final int CONNECT_TIMEOUT = 5000;
	private static final int REQUEST_TIMEOUT = 5000;
	private static final int OK = 200;
	private static final int RETRY_TOTAL = 3;
	private int m_retryCount = 0;  
	
	private static HttpRequestClient m_instance;
	
    private HttpRequestClient() {
    	
    }
    
    public static HttpRequestClient getInstance() {
    	if(m_instance == null) {
    		m_instance = new HttpRequestClient();
    	}
    	return m_instance;
    }

    public void post(String url, String buffer, String outString) throws Exception{
    
    	HttpURLConnection connection = null;
		OutputStream outputStream = null;
		try {
			connection = (HttpURLConnection) new URL(url).openConnection();
			connection.setRequestMethod("POST");
			connection.setDoInput(true);
			connection.setDoOutput(true);
		} 
		catch (Exception e) {
			throw (e);
		}
		
		connection.setConnectTimeout(CONNECT_TIMEOUT);
		connection.setReadTimeout(REQUEST_TIMEOUT);
		connection.setRequestProperty("Content-Type", "text/xml");
		byte[] bytes = null;
		
		try {
			bytes = buffer.getBytes("UTF-8");
		} 
		catch (Exception e) {
			throw (e);
		}

		connection.setRequestProperty("Content-Length",
				Integer.toString(bytes.length));
		outputStream = null;
		try {
			outputStream = connection.getOutputStream();
			outputStream.write(bytes);
			outputStream.flush();
			outputStream.close();
		} 
		catch (Exception e) {
			throw (e);
		}

		int responseCode = -1;
		try {
			responseCode = connection.getResponseCode();
		} catch (Exception e) {
			throw (e);
		}
		if (responseCode != OK) {
			throw new HttpRequestException(responseCode);
		}
		
		InputStream inputStream = connection.getInputStream();
		StringBuffer responseBuffer = new StringBuffer();
		try {
			BufferedReader bufferReader = new BufferedReader(
					new InputStreamReader(inputStream));
			String line = bufferReader.readLine();
			while (line != null){
				responseBuffer.append(line);
				line = bufferReader.readLine();
			}
		} 
		catch (Exception e) {
			throw new Exception(e.getMessage(), e);
		}
		outString = responseBuffer.toString();
    }
    
	public void post(String url, ArrayList<NameValuePair> paramsList, StringBuilder outString) 
			throws Exception {
         HttpEntityEnclosingRequestBase httpRequest =new HttpPost(url);
         httpRequest.setEntity(new UrlEncodedFormEntity(paramsList,HTTP.UTF_8));
         HttpResponse httpResponse = null;
         try {
        	 httpResponse = getHttpClient().execute(httpRequest);
         }
         catch(Exception e) {
        	 if(m_retryCount < RETRY_TOTAL) {
        		 m_retryCount ++;
        		 HttpRequestClient.getInstance().post(url, paramsList, outString);
        	 }
        	 else {
        		 throw(e);
        	 }
         }
         StatusLine statusLine = httpResponse.getStatusLine();
         int statusCode = statusLine.getStatusCode();
         if(statusCode == 200){
        	 outString.append(EntityUtils.toString(httpResponse.getEntity()));
         }
         else{
        	 if(m_retryCount < RETRY_TOTAL) {
        		 m_retryCount ++;
        		 HttpRequestClient.getInstance().post(url, paramsList, outString);
        	 }
        	 else {
        		 throw new HttpRequestException(statusCode);
        	 }
         }
    }
	
	public void get(String url, StringBuilder outString) throws Exception{
		 HttpRequestBase httpRequest =new HttpGet(url);
         //execute the post and get the response from servers
         HttpResponse httpResponse = getHttpClient().execute(httpRequest);
         StatusLine statusLine = httpResponse.getStatusLine();
         int statusCode = statusLine.getStatusCode();
         if(statusCode == 200){
        	 outString.append(EntityUtils.toString(httpResponse.getEntity()));
         }
         else{
        	 throw new HttpRequestException(statusCode);
         }
	}
	
	public void post(String url, String outString) {
		post(url, outString);
	}
	
	public void post(String url, ArrayList<NameValuePair> paramsList, byte[] outBuffer) throws Exception {
		HttpEntity resEntity = null;
		post(url, paramsList,resEntity);
		outBuffer = (resEntity == null) ? null : EntityUtils.toByteArray(resEntity);
	}
	
	public void post(String url, byte[] outBuffer) throws Exception {
		HttpEntity resEntity = null;
		post(url, null,resEntity);
		outBuffer = (resEntity == null) ? null : EntityUtils.toByteArray(resEntity);
	}
	
	private void post(String url, ArrayList<NameValuePair> paramsList, HttpEntity outEntity) 
			throws Exception {

		HttpPost request = new HttpPost(url);
		
		if(paramsList != null) {
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramsList, CHARSET);
			request.setEntity(entity);
		}
		HttpClient client = getHttpClient();
		HttpResponse response = client.execute(request);
		int statusCode = response.getStatusLine().getStatusCode(); 
		if(statusCode != HttpStatus.SC_OK) {
			throw new HttpRequestException(statusCode);	
		}
		outEntity = response.getEntity();
	}
	
	private static synchronized HttpClient getHttpClient() {
		HttpClient httpClient = null;
        if (null == httpClient) {
            HttpParams params = new BasicHttpParams();
            
            // 设置基本参数
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, CHARSET);
            HttpProtocolParams.setUseExpectContinue(params, true);
            HttpProtocolParams.setUserAgent(params, USER_AGENT);
            
            // 超时设置
            ConnManagerParams.setTimeout(params, GET_CONNECTION_TIMEOUT);
            HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT);
            HttpConnectionParams.setSoTimeout(params, REQUEST_TIMEOUT);

            // 设置支持HTTP和HTTPS两种模式
            SchemeRegistry schReg = new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            schReg.register(new Scheme("https", SSLSocketFactory
                    .getSocketFactory(), 443));
            
            // 使用线程安全的连接管理来创建HttpClient
            ClientConnectionManager conMgr = new ThreadSafeClientConnManager(
                    params, schReg);
            httpClient = new DefaultHttpClient(conMgr, params);
        }
        return httpClient;
    }
}
